package com.demo.supplier.service.impl;

import cn.hutool.core.util.StrUtil;
import com.demo.supplier.config.RabbitMqConfig;
import com.demo.supplier.entity.LoginLog;
import com.demo.supplier.entity.OperationLog;
import com.demo.supplier.mapper.LoginLogRepository;
import com.demo.supplier.mapper.OperationLogRepository;
import com.demo.supplier.service.LogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 日志服务实现类
 * 
 * @author demo
 */
@Slf4j
@Service
public class LogServiceImpl implements LogService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OperationLogRepository operationLogRepository;

    @Autowired
    private LoginLogRepository loginLogRepository;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void saveOperationLog(OperationLog operationLog) {
        try {
            rabbitTemplate.convertAndSend(
                    RabbitMqConfig.LOG_TOPIC_EXCHANGE,
                    RabbitMqConfig.OPERATION_LOG_ROUTING_KEY,
                    operationLog
            );
        } catch (Exception e) {
            log.error("发送操作日志消息失败", e);
        }
    }

    @Override
    public void saveLoginLog(LoginLog loginLog) {
        try {
            rabbitTemplate.convertAndSend(
                    RabbitMqConfig.LOG_TOPIC_EXCHANGE,
                    RabbitMqConfig.LOGIN_LOG_ROUTING_KEY,
                    loginLog
            );
        } catch (Exception e) {
            log.error("发送登录日志消息失败", e);
        }
    }

    @Override
    public Page<OperationLog> pageOperationLogs(int page, int size, String keyword) {
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime"));
        
        Query query = new Query();
        if (StrUtil.isNotBlank(keyword)) {
            Criteria criteria = new Criteria().orOperator(
                    Criteria.where("username").regex(keyword, "i"),
                    Criteria.where("operation").regex(keyword, "i"),
                    Criteria.where("module").regex(keyword, "i"),
                    Criteria.where("description").regex(keyword, "i")
            );
            query.addCriteria(criteria);
        }
        
        query.with(pageable);
        
        List<OperationLog> logs = mongoTemplate.find(query, OperationLog.class);
        
        return PageableExecutionUtils.getPage(logs, pageable, () -> {
            Query countQuery = new Query();
            if (StrUtil.isNotBlank(keyword)) {
                Criteria criteria = new Criteria().orOperator(
                        Criteria.where("username").regex(keyword, "i"),
                        Criteria.where("operation").regex(keyword, "i"),
                        Criteria.where("module").regex(keyword, "i"),
                        Criteria.where("description").regex(keyword, "i")
                );
                countQuery.addCriteria(criteria);
            }
            return mongoTemplate.count(countQuery, OperationLog.class);
        });
    }

    @Override
    public Page<LoginLog> pageLoginLogs(int page, int size, String keyword) {
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime"));
        
        Query query = new Query();
        if (StrUtil.isNotBlank(keyword)) {
            Criteria criteria = new Criteria().orOperator(
                    Criteria.where("username").regex(keyword, "i"),
                    Criteria.where("loginType").regex(keyword, "i"),
                    Criteria.where("loginResult").regex(keyword, "i"),
                    Criteria.where("ip").regex(keyword, "i")
            );
            query.addCriteria(criteria);
        }
        
        query.with(pageable);
        
        List<LoginLog> logs = mongoTemplate.find(query, LoginLog.class);
        
        return PageableExecutionUtils.getPage(logs, pageable, () -> {
            Query countQuery = new Query();
            if (StrUtil.isNotBlank(keyword)) {
                Criteria criteria = new Criteria().orOperator(
                        Criteria.where("username").regex(keyword, "i"),
                        Criteria.where("loginType").regex(keyword, "i"),
                        Criteria.where("loginResult").regex(keyword, "i"),
                        Criteria.where("ip").regex(keyword, "i")
                );
                countQuery.addCriteria(criteria);
            }
            return mongoTemplate.count(countQuery, LoginLog.class);
        });
    }

    @Override
    public long countTodayOperationLogs() {
        LocalDateTime startOfDay = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime endOfDay = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(999000000);

        Query query = new Query();
        query.addCriteria(Criteria.where("createTime").gte(startOfDay).lte(endOfDay));
        return mongoTemplate.count(query, OperationLog.class);
    }

    /**
     * 处理操作日志消息
     */
    @RabbitListener(queues = RabbitMqConfig.OPERATION_LOG_QUEUE)
    public void handleOperationLog(OperationLog operationLog) {
        try {
            operationLogRepository.save(operationLog);
            log.debug("保存操作日志成功：{}", operationLog.getDescription());
        } catch (Exception e) {
            log.error("保存操作日志失败", e);
        }
    }

    /**
     * 处理登录日志消息
     */
    @RabbitListener(queues = RabbitMqConfig.LOGIN_LOG_QUEUE)
    public void handleLoginLog(LoginLog loginLog) {
        try {
            loginLogRepository.save(loginLog);
            log.debug("保存登录日志成功：{}", loginLog.getUsername());
        } catch (Exception e) {
            log.error("保存登录日志失败", e);
        }
    }
}